import pytest

from streamlink import Streamlink
from streamlink.stream.dash import DASHStream
from streamlink.stream.file import FileStream
from streamlink.stream.hls import HLSStream
from streamlink.stream.http import HTTPStream
from streamlink.stream.rtmpdump import RTMPStream
from streamlink.stream.stream import Stream
from tests.mock import Mock


@pytest.fixture(scope="module")
def session():
    return Streamlink()


@pytest.fixture(scope="module")
def common_args():
    return dict(
        params={"queryparamkey": "queryparamval"},
        unknown="invalid",
    )


def test_base_stream(session):
    stream = Stream(session)
    with pytest.raises(TypeError) as cm:
        stream.to_url()
    assert str(cm.value) == "<Stream [stream]> cannot be translated to a URL"
    with pytest.raises(TypeError) as cm:
        stream.to_manifest_url()
    assert str(cm.value) == "<Stream [stream]> cannot be translated to a manifest URL"


def test_file_stream_handle(session):
    stream = FileStream(session, None, Mock())
    with pytest.raises(TypeError) as cm:
        stream.to_url()
    assert str(cm.value) == "<FileStream [file]> cannot be translated to a URL"
    with pytest.raises(TypeError) as cm:
        stream.to_manifest_url()
    assert str(cm.value) == "<FileStream [file]> cannot be translated to a manifest URL"


def test_file_stream_path(session):
    stream = FileStream(session, "/path/to/file")
    assert stream.to_url() == "/path/to/file"
    with pytest.raises(TypeError) as cm:
        stream.to_manifest_url()
    assert str(cm.value) == "<FileStream [file]> cannot be translated to a manifest URL"


def test_http_stream(session, common_args):
    stream = HTTPStream(session, "http://host/stream?foo=bar", **common_args)
    assert stream.to_url() == "http://host/stream?foo=bar&queryparamkey=queryparamval"
    with pytest.raises(TypeError) as cm:
        stream.to_manifest_url()
    assert str(cm.value) == "<HTTPStream [http]> cannot be translated to a manifest URL"


def test_hls_stream(session, common_args):
    stream = HLSStream(session, "http://host/stream.m3u8?foo=bar", **common_args)
    assert stream.to_url() == "http://host/stream.m3u8?foo=bar&queryparamkey=queryparamval"
    with pytest.raises(TypeError) as cm:
        stream.to_manifest_url()
    assert str(cm.value) == "<HLSStream [hls]> cannot be translated to a manifest URL"


def test_hls_stream_master(session, common_args):
    stream = HLSStream(session, "http://host/stream.m3u8?foo=bar", "http://host/master.m3u8?foo=bar", **common_args)
    assert stream.to_url() == "http://host/stream.m3u8?foo=bar&queryparamkey=queryparamval"
    assert stream.to_manifest_url() == "http://host/master.m3u8?foo=bar&queryparamkey=queryparamval"


def test_rtmp_stream(session):
    stream = RTMPStream(
        session,
        {
            "rtmp": "rtmp://test.se/app/play_path",
            "swfVfy": "http://test.se/player.swf",
            "swfhash": "test",
            "swfsize": 123456,
            "playPath": "play_path"
        }
    )
    expected = "rtmp://test.se/app/play_path playPath=play_path swfUrl=http://test.se/player.swf swfVfy=1"
    assert stream.to_url() == expected


def test_dash_stream(session):
    mpd = Mock(url=None)
    stream = DASHStream(session, mpd)
    with pytest.raises(TypeError) as cm:
        stream.to_url()
    assert str(cm.value) == "<DASHStream [dash]> cannot be translated to a URL"
    with pytest.raises(TypeError) as cm:
        stream.to_manifest_url()
    assert str(cm.value) == "<DASHStream [dash]> cannot be translated to a manifest URL"


def test_dash_stream_url(session, common_args):
    # DASHStream requires an MPD instance as input:
    # The URL of the MPD instance was already prepared by DASHStream.parse_manifest, so copy this behavior here.
    # This test verifies that session params are added to the URL, without duplicates.
    args = common_args.copy()
    args.update(url="http://host/stream.mpd?foo=bar")
    url = session.http.prepare_new_request(**args).url
    mpd = Mock(url=url)
    stream = DASHStream(session, mpd, **common_args)
    assert stream.to_url() == "http://host/stream.mpd?foo=bar&queryparamkey=queryparamval"
    with pytest.raises(TypeError) as cm:
        stream.to_manifest_url()
    assert str(cm.value) == "<DASHStream [dash]> cannot be translated to a manifest URL"
